#include <gtk/gtk.h>
#include "vcd-refresh-vm-info.h"
#include "vcd-vm-connect.h"
#include "vcd-get-vm-info.h"
#include "vcd-conf/vcd-conf.h"
#include "vcd-json-parser.h"
#include "vcd-common.h"
#include "vcd-linux-ui/vcd-logined-window.h"
#include "vcd-util.h"
#include "vcd-download.h"
#include "spicy.h"
#include "vcd-vm-rdp-connect.h"
#include "vcd-get-login-ticket.h"
#include "vcd-conf/vcd-conf.h"

typedef struct _RefreshContext{
	GThread *refresh_thread;
	GMutex* thd_mutex;
    GCond*  thd_cond;
    guint   timer_index;
    volatile gboolean refresh_flag;
    gint    visibile;
    guint   fresh_ticket_index;
}RefreshContext;

static RefreshContext* g_rc = NULL;

int g_timeout_set_main_vbox = 0;

static gboolean refresh_vm_info_task(void);
static gboolean refresh_vm_info_in_thread(void);
static void free_refresh_context(void);
static int create_refresh_context(void);
static void start_fresh_ticket_and_vm_list(RefreshContext *rc);
static void stop_fresh_ticket(RefreshContext *rc);
static void stop_fresh_vm_list(RefreshContext *rc);
static gboolean fresh_ticket_param_func(void);
gboolean visibility_notify_handler(GtkWidget* widget, GdkEventVisibility *event, gpointer data);

static void free_refresh_context(void)
{
	if (g_rc == NULL)
		return;

    if (g_rc->refresh_thread) {
        g_thread_unref(g_rc->refresh_thread);
        g_rc->refresh_thread = NULL;
    }

    if (g_rc->thd_mutex) {
        g_mutex_clear(g_rc->thd_mutex);
        g_free(g_rc->thd_mutex);
        g_rc->thd_mutex = NULL;
    }
    if (g_rc->thd_cond){
        g_cond_clear(g_rc->thd_cond);
        g_free(g_rc->thd_cond);
        g_rc->thd_cond = NULL;
    }

    g_free(g_rc);
	g_rc = NULL;
}

static int create_refresh_context(void)
{
    GMutex* thd_mutex = NULL;
	GCond*  thd_cond = NULL;

    RefreshContext* rc = (RefreshContext*)g_malloc0(sizeof(RefreshContext));
	g_return_val_if_fail(rc != NULL, -1);

    thd_mutex = g_malloc0(sizeof(GMutex));
	if (thd_mutex == NULL) {
		LOG_ERROR("new mutex failed");
		goto fail;
	}
    thd_cond = g_malloc0(sizeof(GCond));
	if (thd_cond == NULL) {
		LOG_ERROR("new cond failed");
		goto fail;
	}
    g_mutex_init(thd_mutex);
    g_cond_init(thd_cond);

    rc->thd_cond  = thd_cond;
    rc->thd_mutex = thd_mutex;
	rc->refresh_flag = TRUE;
    rc->visibile = 1;
    rc->fresh_ticket_index = 0;
    rc->timer_index = 0;
    g_rc = rc;
	return 0;

fail:
	if (thd_mutex) {
        g_mutex_clear(thd_mutex);
		thd_mutex = NULL;
	}
	free(rc);
	rc = NULL;
	return -1;
}

void stop_refresh_thread(void)
{
    if (g_rc == NULL)
        return ;

    stop_fresh_ticket(g_rc);
    stop_fresh_vm_list(g_rc);

	g_rc->refresh_flag = FALSE;
	g_return_if_fail(g_rc != NULL);

    g_mutex_lock(g_rc->thd_mutex);
	g_cond_signal(g_rc->thd_cond);
	g_mutex_unlock(g_rc->thd_mutex);

    //wait thread exit
	g_thread_join(g_rc->refresh_thread);
    g_rc->refresh_thread = NULL;

	free_refresh_context();
}

static gboolean fresh_ticket_param_func(void)
{
    M_DEBUG("fresh_ticket_param_func");
    start_get_ticket(ACTION_FRESH_TICKET);
    return TRUE;
}

static void start_fresh_ticket_and_vm_list(RefreshContext *rc)
{
    struct vcd_conf *cf = g_vcd_conf;
    // uint64_t cur = get_time();
    // if (cur - g_last_fresh_ticket_time >= cf->fresh_ticket_interval) {
    //     fresh_ticket_param_func();
    // }
    rc->fresh_ticket_index = g_timeout_add_seconds(cf->fresh_ticket_interval, 
                                    (GSourceFunc)fresh_ticket_param_func, NULL);
    rc->timer_index = g_timeout_add_seconds(cf->fresh_vm_list_interval,
                                            (GSourceFunc)set_main_vbox_fun, NULL);
}

static void stop_fresh_ticket(RefreshContext *rc)
{
    if (rc->fresh_ticket_index != 0) {
        g_source_remove(rc->fresh_ticket_index);
        rc->fresh_ticket_index = 0;
    }
}

static void stop_fresh_vm_list(RefreshContext *rc)
{
    if (g_rc->timer_index != 0) {
        g_source_remove(g_rc->timer_index);
        g_rc->timer_index = 0;
    }
}

gboolean visibility_notify_handler(GtkWidget* widget, GdkEventVisibility *event, gpointer data)
{
    //M_DEBUG("nofity type:%d window:%p event:%d state:%d",
    //       (int)event->type, event->window, (int)event->send_event, (int)event->state);

    RefreshContext *rc = (RefreshContext*)data;
    switch(event->state)
    {
        case GDK_VISIBILITY_UNOBSCURED:
            //M_DEBUG("event->state = GDK_VISIBILITY_UNOBSCURED");
            rc->visibile = 1;
            break;
        case GDK_VISIBILITY_PARTIAL:
            //M_DEBUG("event->state = GDK_VISIBILITY_PARTIAL");
            rc->visibile = 1;
            break;
        case GDK_VISIBILITY_FULLY_OBSCURED:
            //M_DEBUG("event->state = GDK_VISIBILITY_FULLY_OBSCURED");
            rc->visibile = 0;
            break;
        default:
            //M_DEBUG("event->state = default");
            rc->visibile = 1;
            break;
    }
    return TRUE;
}

gboolean set_main_vbox_fun(void)
{
    if (g_rc == NULL)
        return FALSE;

    if (g_rc->visibile) {
        g_mutex_lock(g_rc->thd_mutex);
        g_cond_signal(g_rc->thd_cond);
        g_mutex_unlock(g_rc->thd_mutex);
    }
    return TRUE;
}

static gboolean refresh_vm_info_task(void)
{
    int res = get_vm_list();
    if (res != 0)
        LOG_ERROR("get vm info failed");
    
    return FALSE;
}

static gboolean refresh_vm_info_in_thread(void)
{
    while (g_rc->refresh_flag) {
        g_mutex_lock(g_rc->thd_mutex);
        g_cond_wait(g_rc->thd_cond, g_rc->thd_mutex);
		if (g_rc->refresh_flag)
        	gdk_threads_add_idle((GSourceFunc)refresh_vm_info_task, NULL);
        g_mutex_unlock(g_rc->thd_mutex);
    }
    return FALSE;
}

int start_refresh_vm_thread(void)
{
    int res = create_refresh_context();
    g_return_val_if_fail(res == 0, -1); 

    //add visibility event for loggined window
    GtkWidget* win = g_logined_window->logined_window_handle;    
    gtk_widget_add_events(win, GDK_VISIBILITY_NOTIFY_MASK);
    g_signal_connect(win, "visibility_notify_event", G_CALLBACK(visibility_notify_handler), g_rc);

    start_fresh_ticket_and_vm_list(g_rc);

    GThread * thd = g_thread_new("refresh_vm_info", (GThreadFunc)refresh_vm_info_in_thread, NULL);
    if (thd == NULL) {
        LOG_ERROR("thd == NULL");
        free_refresh_context();
		return -1;
	}
	g_rc->refresh_thread = thd;
	
    return 0;
}
/**
 *  @pam flag: 1 on   0 off
 */
void set_refresh_vm_info_flag(int flag){
    g_return_if_fail(g_rc != NULL);
    g_rc->visibile = flag;
}